package gov.mogaha.ntis.cmm.mob.view;

import gov.mogaha.ntis.cmm.mob.R;

import java.util.ArrayList;

import android.content.Context;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.ScrollView;
import android.widget.TextView;


/** <B><I>public class AddressListView extends LinearLayout</B></I><BR>
 * 주소 등의 문자열 형태의 아이템을 검색할 때 사용할 수 있는 리스트셋.
 * @author 이전봉
 * @version 1.3
 *
 */
public class AddressListView extends LinearLayout {
	View view;
	private final Context context;
	protected ArrayList<ArrayList<String>> arrItems;
	
	protected TextView textItemCount;
	private boolean hasCustomCounterTextUsed = false;
	protected TextView textNoItems;
	protected LinearLayout layList;
	/**리스트를 상하로 탐색하지 않은 초기 상태에서 표시할 아이템의 수. 기본값으로 5를 갖는다.*/
	private int showingItems = 5;
	protected ListView listAddr;
	protected View footLine;
	
	protected ArrayAdapter<ArrayList<String>> adapterAddr;
	
	
	
	
	/**<B><I>public AddressListView(Context context, AttributeSet attrs)</B></I><BR>
	 * 새로운 AddressListView 개체를 생성한다. 생성 후 반드시 initiate(ArrayList&LTArrayList&LTString&GT&GT arrItems) 
	 * 메소드를 호출해 주어야 리스트가 표시된다.
	 * @param context 애플리케이션 컨텍스트
	 * @param attrs 어트리뷰트셋
	 * @since 1.0
	 */
	public AddressListView(Context context, AttributeSet attrs) {
		super(context, attrs);
		this.context = context;
		
		//인플레이트 및 기본적인 위젯 초기화
		layoutInflate();
		
		//데이터셋 새로고침
		notifyDataSetChanged();
	}
	
	
	
	/**<B><I>public AddressListView(Context context, AttributeSet attrs, ArrayList&LTArrayList&LTString&GT&GT arrItems)</B></I><BR>
	 * 새로운 AddressListView 개체를 생성한다.
	 * @param context 어플리케이션 컨텍스트
	 * @param attrs 어트리뷰트셋
	 * @param arrItems 리스트에서 사용할 데이터셋 리스트
	 * @since 1.2
	 */
	public AddressListView(Context context, AttributeSet attrs, ArrayList<ArrayList<String>> arrItems) {
		super(context, attrs);
		this.context = context;
		
		//인플레이트 및 기본적인 위젯 초기화
		layoutInflate();
		
		//데이터셋 연결
		initiate(arrItems);
		
		//데이터셋 새로고침
		notifyDataSetChanged();
	}
	
	
	
	/**<B><I>private void layoutInflate()</B></I><BR>
	 * 리스트셋의 레이아웃을 인플레이트하고 위젯을 초기화한다.
	 * @since 1.2
	 */
	private void layoutInflate() {
		LayoutInflater inflater = (LayoutInflater) getContext()
				.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
		view = inflater.inflate(R.layout.address_list_view, this, false);
		addView(view);
		
		
		textItemCount = (TextView)findViewById(R.id.text_AddrListView_ItemCount);
		textNoItems = (TextView)findViewById(R.id.text_AddrListView_Sub);
		
		layList = (LinearLayout)findViewById(R.id.lay_AddrListView_List);
	}
	
	
	
	/**<B><I>public void initiate(ArrayList&LTArrayList&LTString&GT&GT arrItems)</B></I><BR>
	 * 지정할 ArrayList를 사용하여 리스트를 초기화한다.
	 * @param arrItems 리스트에 표시될, 아이템이 저장된 혹은 저장될 문자열 배열 리스트
	 * @since 1.0
	 */
	public void initiate(ArrayList<ArrayList<String>> arrItems) {
		this.setVisibility(View.GONE);
		
		listAddr = (ListView)findViewById(R.id.list_AddrListView_List);
		
		//헤더 설정
		setHeader(R.layout.address_list_view_header);
		
		//데이터셋 설정
		setDataset(arrItems);
		
		//어댑터 설정
		setAdapter(new AddressListViewAdapter(context, R.layout.address_list_view_resource, this.arrItems));
		
		//하단 라인 설정
		footLine = (View)findViewById(R.id.view_AddrListView_Line);
	}
	
	
	
	/**<B><I>public &LTT&GT void setAdapter(ArrayAdapter&LTArrayList&LTString&GT&GT arrayAdapter)</B></I><BR>
	 * 리스트에 사용될 어탭터를 설정한다.
	 * @param arrayAdapter 설정할 어댑터
	 * @since 1.3
	 */
	public <T> void setAdapter(ArrayAdapter<ArrayList<String>> arrayAdapter) {
		adapterAddr = arrayAdapter;
		listAddr.setAdapter(adapterAddr);
	}
	
	
	
	/**<B><I>public void setDataset(ArrayList&LTArrayList&LTString&GT&GT arrItems)</B></I><BR>
	 * 리스트에 사용될 데이터셋을 설정한다. null값을 넣을 경우, 비어있는 데이터셋을 새로 생성하여 설정한다.
	 * @param arrItems 사용할 데이터셋. null값을 넣으면 새 데이터셋을 생성하여 설정.
	 * @since 1.3
	 */
	public void setDataset(ArrayList<ArrayList<String>> arrItems) {
		if (arrItems == null)
			this.arrItems = new ArrayList<ArrayList<String>>();
		else
			this.arrItems = arrItems;
	}
	
	
	
	/**<B><I>public void setHeader(int res)</B></I><BR>
	 * 사용자정의된 뷰로 리스트셋의 아이템 헤더를 설정한다.
	 * @param res 사용자정의된 뷰
	 * @throws ClassCastException 잘못된 개체를 매개변수로 사용할 경우
	 * @throws LayoutInflateException 레이아웃 인플레이트에 오류가 발생할 경우
	 * @since 1.3
	 */
	public void setHeader(int res) {
		LayoutInflater headerInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
		View listHeader = headerInflater.inflate(res, null, false);
		listAddr.addHeaderView(listHeader);
	}
	
	
	
	
	/**<B><I>public ArrayList&LTArrayList&LTString&GT&GT getDateset()</B></I><BR>
	 * 리스트에 연결된 문자열 배열을 구한다.
	 * @return <LI>리스트에 연결된 문자열 배열.</LI>
	 * @since 1.0
	 */
	public ArrayList<ArrayList<String>> getDateset() {
		return arrItems;
	}
	
	/**<B><I>public ArrayList&LTString&GT getItem(int position)</B></I><BR>
	 * 해당 위치의 아이템을 데이터셋에서 가져온다.
	 * @param position 가져올 아이템의 위치
	 * @return <LI>해당 위치의 아이템</LI>
	 * @deprecated
	 * @see <LI><B>getItemAtPosition(int position)</B></LI>
	 * @since 1.0
	 */
	public ArrayList<String> getItem(int position) {
		if (adapterAddr == null) return null;
		return adapterAddr.getItem(position);
	}
	
	/**<B><I>public ArrayList&LTString&GT getItemAtPosition(int position)</B></I><BR>
	 * 해당 위치의 아이템을 데이터셋에서 가져온다.
	 * @param position 가져올 아이템의 위치
	 * @return <LI>ArrayList&LTString&GT 형식의 해당 위치의 아이템</LI>
	 * @exception NullPointerException
	 * @since 1.1
	 */
	public ArrayList<String> getItemAtPosition(int position) {
		if (adapterAddr == null) return null;
		return arrItems.get(position-1);
	}
	
	/**<B><I>public String getFullAddressAtPosition(int position)</B></I><BR>
	 * 해당 위치의 문자열 조각들을 하나로 합쳐서 완전한 주소 형식의 문자열을 구한다.
	 * @param position 가져올 아이템의 위치
	 * @return 문자열 형식의 주소
	 * @see <LI><B>getItemAtPosition(int position)</B></LI>
	 * @since 1.3
	 */
	public String getFullAddressAtPosition(int position) {
		if (adapterAddr == null) return "";
		
		ArrayList<String> data = getItemAtPosition(position);
		StringBuilder builder = new StringBuilder();
		int lengh = data.size();
		for (int i=0; i<lengh; i++) {
			String str = data.get(i);
			builder.append(str);
			if (i<lengh-1 && str!="") {
				builder.append(" ");
			}
		}
		
		return builder.toString();
	}
	
	/**<B><I>public void changeDataset(ArrayList&LTArrayList&LTString&GT&GT list)</B></I><BR>
	 * 리스트에 연결된 문자열 배열을 다른 배열로 바꾼다.
	 * @param list 새로 바꿀 문자열 배열
	 * @since 1.0
	 */
	public void changeDataset(ArrayList<ArrayList<String>> list) {
		this.arrItems = list;
		notifyDataSetChanged();
	}
	
	
	
	/**<B><I>public int getDatasetSize()</B></I><BR>
	 * 리스트에 연결된 문자열 배열의 크기를 구한다.
	 * @return <LI>리스트에 연결된 문자열 배열의 크기</LI>
	 * @deprecated
	 * @see <LI><B>size()</B></LI>
	 * @since 1.0
	 */
	public int getDatasetSize() {
		if (arrItems != null)
			return arrItems.size();
		else
			return 0;
	}
	
	/**<B><I>public int size()</B></I><BR>
	 * 리스트에 연결된 문자열 배열의 크기를 구한다.
	 * @return <LI>리스트에 연결된 문자열 배열의 크기</LI>
	 * @since 1.1
	 */
	public int size() {
		if (arrItems != null)
			return arrItems.size();
		else
			return 0;
	}
	
	/**<B><I>public void notifyDataSetChanged()</B></I><BR>
	 * 데이터셋에 데이터가 새로 추가되거나 삭제되는 등 내용이 변경되었을 때, 
	 * 이 메소드를 호출하면 리스트뷰에 데이터의 변경을 통지하여 위젯 내용을 새로고침 한다.
	 * @since 1.0
	 */
	public void notifyDataSetChanged() {
		if (adapterAddr != null)
			adapterAddr.notifyDataSetChanged();
		setLayoutHeightByItemCount();
		
		if (!hasCustomCounterTextUsed)
			setCounterText();
	}
	
	
	
	/**<B><I>setCounterText()</B></I><BR>
	 * 검색된 항목 수가 표시된다.
	 * @see <LI><B>setCounterText(String msg)</B></LI>
	 * @see <LI><B>hasCustomCounterTextUsed()</B></LI>
	 * @since 1.0
	 */
	public void setCounterText() {
		textItemCount.setText("(검색됨: "+getDatasetSize()+")");
		hasCustomCounterTextUsed = false;
	}
	
	
	/**<B><I>setCounterText(String msg)</B></I><BR>
	 * 검색된 항목 수를 표시하는 부분의 텍스트를 새로 설정한다. 
	 * 이 메소드를 호출한 후에는 notifyDataSetChanged() 메소드를 호출해도 
	 * 검색된 항목 수 텍스트가 자동으로 변경되지 않으므로 직접 고쳐주어야한다.
	 * @param msg 설정할 텍스트
	 * @see <LI><B>setCounterText()</B></LI>
	 * @see <LI><B>hasCustomCounterTextUsed()</B></LI>
	 * @since 1.2
	 */
	public void setCounterText(String msg) {
		textItemCount.setText(msg);
		hasCustomCounterTextUsed = true;
	}
	
	
	/**<B><I>public boolean hasCustomCounterTextUsed()</B></I><BR>
	 * 검색된 항목 수를 표시하는 부분의 텍스트를 기본 텍스트로 표시중인지, 
	 * 재설정된 텍스트로 표시중인지를 확인한다.
	 * @return <LI>재설정된 텍스트로 표시중이라면 true, 
	 * 기본 텍스트로 표시중이라면 false 리턴됨.</LI>
	 * @since 1.2
	 */
	public boolean hasCustomCounterTextUsed() {
		return hasCustomCounterTextUsed;
	}
	
	
	
	/**<B><I>setLayoutHeightByItemCount()</B></I><BR>
	 * 아이템의 표시 갯수에 따라 레이아웃의 높이를 자동으로 설정한다. 
	 * 표시할 아이템의 갯수는 setShowingItems(int count) 메소드로 지정할 수 있다.
	 * @see <LI><B>setShowingItems(int count)</B></LI>
	 * @since 1.0
	 */
	public void setLayoutHeightByItemCount() {
		if (arrItems==null || arrItems.size()==0) {
			textNoItems.setVisibility(View.VISIBLE);
			layList.setVisibility(View.GONE);
		} else {
			int itemCount;
			if (adapterAddr == null) itemCount = 0;
			else itemCount = adapterAddr.getCount();
			
			int height = 0;
			if (itemCount >= showingItems) {
				height = getResources().getDimensionPixelSize(R.dimen.addr_jibun_list_item_height_header) + 
						(getResources().getDimensionPixelSize(R.dimen.addr_jibun_list_item_height))*showingItems;
			} else {
				height = getResources().getDimensionPixelSize(R.dimen.addr_jibun_list_item_height_header) + 
						(getResources().getDimensionPixelSize(R.dimen.addr_jibun_list_item_height))*itemCount;
			}
			
			android.view.ViewGroup.LayoutParams params = layList.getLayoutParams();
			params.height = height;
			layList.setLayoutParams(params);
			layList.setVisibility(View.VISIBLE);
			textNoItems.setVisibility(View.GONE);
		}
	}
	
	/**<B><I>setShowingItems(int count)</B></I><BR>
	 * 리스트를 상하로 탐색하지 않은 초기 상태에서 표시할 아이템의 수를 지정할 수 있다.
	 * @deprecated
	 * @param count 표시할 아이템의 갯수
	 * @see <LI><B>setShowingItemCount(int count)</B></LI>
	 * @since 1.0
	 */
	public void setShowingItems(int count) {
		this.showingItems = count;
	}
	
	
	/** <B><I>public void setShowingItemCount(int count)</B></I><BR>
	 * 리스트를 상하로 탐색하지 않은 초기 상태에서 표시할 아이템의 수를 지정할 수 있다.
	 * @param count 표시할 아이템의 갯수
	 * @since 1.2
	 */
	public void setShowingItemCount(int count) {
		this.showingItems = count;
	}
	
	
	
	/**<B><I>public void setLineVisible(boolean visible)</B></I><BR>
	 * 리스트 하단에 선을 표시할 것인지를 설정한다.
	 * @param visible true를 넣으면 표시, false는 표시하지 않는다. 기본값으로 true를 갖는다.
	 * @deprecated
	 * @see <LI><B>setListFootLineVisible(boolean visible)</B></LI>
	 * @since 1.0
	 */
	public void setLineVisible(boolean visible) {
		if (visible)
			footLine.setVisibility(View.VISIBLE);
		else
			footLine.setVisibility(View.GONE);
	}
	
	/**<B><I>public void setListFootLineVisible(boolean visible)</B></I><BR>
	 * 리스트 하단에 선을 표시할 것인지를 설정한다.
	 * @param visible 매개변수로 true를 넣으면 표시, false는 표시하지 않는다.
	 * @since 1.2
	 */
	public void setListFootLineVisible(boolean visible) {
		if (visible)
			footLine.setVisibility(View.VISIBLE);
		else
			footLine.setVisibility(View.GONE);
	}
	
	
	
	/**<B><I>public void setOnItemClickListener(OnItemClickListener event)</B></I><BR>
	 * 아이템을 클릭했을 때의 이벤트 리스너를 설정한다.
	 * @param event OnItemClickListener
	 * @since 1.0
	 */
	public void setOnItemClickListener(OnItemClickListener event) {
		listAddr.setOnItemClickListener(event);
	}
	
	
	
	/**<B><I>public void show()</B></I><BR>
	 * 레이아웃과 아이템 리스트를 표시한다.
	 * @see <LI><B>gone()</B></LI>
	 * @since 1.0
	 */
	public void show() {
		notifyDataSetChanged();
		super.setVisibility(View.VISIBLE);
	}
	
	/**<B><I>public void gone()</B></I><BR>
	 * 레이아웃과 아이템 리스트를 사라지게 한다.
	 * @see <LI><B>show()</B></LI>
	 * @since 1.0
	 */
	public void gone() {
		super.setVisibility(View.GONE);
	}
	
	
	
	/**<B><I>public void setVisibility(int visibility)</B></I><BR>
	 * 뷰의 가시성을 설정한다.
	 * @param visibility 뷰의 가시성. View개체의 static변수-VISIBLE, INVISIBLE, GONE-를 사용할 수 있다.
	 * @see <LI><B>show()</B></LI>
	 * @see <LI><B>gone()</B></LI>
	 * @since 1.2
	 */
	@Override
	public void setVisibility(int visibility) {
		switch (visibility) {
		case View.VISIBLE :
			show();
			break;
		default :
			super.setVisibility(visibility);
			break;
		}
	}
	
	
	
	/**<B><I>public ListView getListView()</B></I><BR>
	 * 리스트뷰를 구한다.
	 * @return 리스트뷰
	 * @since 1.3
	 */
	public ListView getListView() {
		return listAddr;
	}
	
	
	
	/**<B><I>public void setTouchIntercepter(final ScrollView root)</B></I><BR>
	 * 루트 스크롤뷰 내에서 리스트셋을 스크롤 할 경우, 루트의 터치 이벤트를 리스트뷰의 터치 액션으로 전달하여 
	 * 리스트뷰에 이벤트가 적용되도록 한다.
	 * @param root 루트 스크롤뷰
	 * @author 함태영
	 * @since 1.3
	 */
	public void setTouchIntercepter(final ScrollView root) {
		listAddr.setOnTouchListener(new OnTouchListener() {
			@Override
			public boolean onTouch(View v, MotionEvent event) {
				ScrollView scroll = root;
				scroll.requestDisallowInterceptTouchEvent(true);
				return false;
			}
		});
	}
}

































